﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;

namespace TechnicalAnalysisEngine.Tests
{
    [TestClass]
    public class TestStochastic
    {
        List<double> highs;
        List<double> lows;
        List<double> closes;
        List<double> expectedKValues;

        [TestInitialize]
        public void Initialize()
        {
            highs = new List<double>()
            {
                127.01,127.62,126.59,127.35,128.17,128.43,127.37,126.42,126.90,126.85,125.65,125.72,
                127.16,127.72,127.69,128.22,128.27,128.09,128.27,127.74,128.77,129.29,130.06,129.12,
                129.29,128.47,128.09,128.65,129.14,128.64
            };

            lows = new List<double>()
            {
                125.36,126.16,124.93,126.09,126.82,126.48,126.03,124.83,126.39,125.72,124.56,
                124.57,125.07,126.86,126.63,126.80,126.71,126.80,126.13,125.92,126.99,127.81,
                128.47,128.06,127.61,127.60,127.00,126.90,127.49,127.40
            };

            closes = new List<double>()
            {
                1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,127.29,127.18,128.01,
                127.11,127.73,127.06,127.33,128.71,127.87,128.58,128.60,127.93,128.11,127.60,127.60,128.69,128.27
            };

            expectedKValues = new List<double>()
            {
                70.44,67.61,89.20,65.81,81.75,64.52,74.53,98.58,70.10,
                73.06,73.42,61.23,60.96,40.39,40.39,66.83,56.73
            };
        }

        [TestMethod]
        public void TestStochasticResultCount()
        {
            int kPeriod = 14;
            int dPeriod = 3;

            var result = AnalysisEngine.Stochastic(highs, lows, closes, kPeriod, dPeriod);

            Assert.AreEqual(17, result.KLine.Count);
            Assert.AreEqual(15, result.DLine.Count);

            Assert.AreEqual(13, result.KStartIndexOffset);
            Assert.AreEqual(15, result.DStartIndexOffset);
        }

        [TestMethod]
        public void TestStochasticValues()
        {
            int kPeriod = 14;
            int dPeriod = 3;

            var result = AnalysisEngine.Stochastic(highs, lows, closes, kPeriod, dPeriod);

            string message = null;
            bool testResult = true;

            for (int i = 0; i < result.KLine.Count; i++)
            {
                if ((int)(result.KLine[i]) != (int)(expectedKValues[i]))
                {
                    if (!TestHelpers.EqualsWithTolerance(result.KLine[i], expectedKValues[i], 1)) // 1% tolerance from expected results
                    {
                        message = string.Format("Values do not match at position {0}, expected: {1}, actual: {2} ",
                                                 i, expectedKValues[i], result.KLine[i]);
                        testResult = false;
                        break;
                    }
                }
            }

            Assert.IsTrue(testResult, message);
        }

        [TestMethod]
        public void TestStochasticPerformance()
        {
            int kPeriod = 14;
            int dPeriod = 3;

            Random random = new Random();
            var randomlyGeneratedValues = new List<double>();

            for (int i = 0; i < 10000; i++)
            {
                randomlyGeneratedValues.Add(random.Next(85, 90));
            }

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            AnalysisEngine.Stochastic(randomlyGeneratedValues, randomlyGeneratedValues, randomlyGeneratedValues, kPeriod, dPeriod);
            
            stopWatch.Stop();
            Console.WriteLine(string.Format("Stochastic, {0} values, {1} μs", randomlyGeneratedValues.Count, stopWatch.ElapsedTicks / 10));
        }
    }
}
